/**
 * This file is released under the GNU General Public License.
 * Refer to the COPYING file distributed with this package.
 *
 * Copyright (c) 2008-2009 WURFL-Pro srl
 */
package net.sourceforge.wurfl.core;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Map;

import org.apache.commons.lang.text.StrBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * {@link CapabilitiesHolder} default implementation.
 * <p>
 * This is the default implementation of CapabilitiesHolder, it use a Map to
 * store capabilities and a CapabilitiesLoader implementation to lazily load
 * capabilities values.
 * </p>
 * 
 * <p>
 * It is very efficient if you need getting more then one capability, and if
 * you want getting capability from JSTL, because you can't use
 * getCapability("name") from there but you can grab capability by doing
 * ${device.capabilities.name}.
 * </p>
 * 
 * @author WURFL-PRO SRL, Rome, Italy
 * @version $Id: DefaultCapabilitiesHolder.java 1045 2009-03-09 15:52:53Z filippo.deluca $
 */
public class DefaultCapabilitiesHolder implements CapabilitiesHolder,
		Serializable {

	/** serial */
	private static final long serialVersionUID = 100L;

	/** log */
	private static final Log log = LogFactory.getLog(DefaultCapabilitiesHolder.class);

	/**
	 * Capability loader will not serialized because it can referencing the
	 * Model
	 */
	private transient CapabilitiesLoader capabilitiesLoader;

	/** The map where the capabilities are stored */
	private Map capabilities;


	public DefaultCapabilitiesHolder(CapabilitiesLoader capabilitiesLoader) {
		this.capabilitiesLoader = capabilitiesLoader;
	}

	public String getCapabilityValue(String capabilityName) throws CapabilityNotDefinedException {

		String value = (String) getAllCapabilities().get(capabilityName);
		
		if (log.isTraceEnabled()) {
			StrBuilder msgBuilder = new StrBuilder();
			msgBuilder.append("Get capability: ").append(capabilityName).append(" = ").append(value);
			
			log.trace(msgBuilder.toString());
		}
		
		if(value==null){
			throw new CapabilityNotDefinedException(capabilityName);
		}
		else{
			return value;
		}
	}

	public Map getAllCapabilities() {
		if (this.capabilities == null) {

			if (capabilitiesLoader == null) {
				throw new IllegalStateException(
						"The device must be initialized before serialization");
			} else {
				log.debug("Initializing capabilities");
				this.capabilities = capabilitiesLoader.loadCapabilities();
			}
		}

		assert capabilities != null;

		return capabilities;
	}
	
	// Serialization ******************************************************

	private void writeObject(ObjectOutputStream out) throws IOException {

		if (this.capabilities == null) {
			this.capabilities = capabilitiesLoader.loadCapabilities();
		}

		out.defaultWriteObject();
	}
	

}
